<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Document</title>
  <style>
    body {
      display: flex;
      flex-direction: column;
      align-items: center;
    }

    .container {
      width: 500px;
      height: 300px;
      overflow: hidden;

    }

    .swiper-container {
      /* width: 100%; */
      height: 100%;
      display: flex;

    }

    .swiper-item {
      width: 100%;
      height: 100%;
      flex-shrink: 0;
    }

    .swiper-item img {
      width: 100%;
      height: 100%;
    }
  </style>
</head>

<body>
  <div class="container"></div>
  <button id="next">next</button>
  <button id="pre">pre</button>
  <script>
    let arr = [
      {
        src: "./static/1.jpg",
      },
      {
        src: "./static/2.jpg",
      },
      {
        src: "./static/3.jpg",
      },
      {
        src: "./static/4.jpg",
      },
      {
        src: "./static/5.jpg",
      },
    ];
    class Utils {
      static createDom (classList = []) {

        let dom = document.createElement("div");
        classList.forEach((item) => dom.classList.add(item))
        return dom
      }
      static append (son, par = document.body) {
        par.appendChild(son)
      }
      static getDom (className) {
        return document.querySelector(className)
      }
      static debounce (func, wait) {
        let timeoutId;

        return function (...args) {
          console.log("debounce", this)
          clearTimeout(timeoutId);
          timeoutId = setTimeout(() => {
            //这个this，指向的是调用的闭包函数的this
            func.apply(this, args);
          }, wait);
        };
      }
      static singleExecutionFunction (callback) {
        let isExecuting = false;
        let pendingPromise;

        return function (...args) {
          if (isExecuting) {
            // 如果已经在执行，则等待当前执行完成
            return pendingPromise;
          }

          isExecuting = true;
          pendingPromise = new Promise((resolve) => {
            callback(...args).then(() => {
              isExecuting = false;
              resolve();
            });
          });

          return pendingPromise;
        };
      }

    }
    class Silder {
      domArr;
      swiperContainer;
      sp_container;
      index = new Proxy({ value: 0 }, this.#subscription(this));
      constructor(obj) {
        this.container = Utils.getDom(obj.container);
        this.arr = obj.arr;
        this.containerWidth = this.container.getBoundingClientRect().width;
        this.loop = typeof obj.loop ? obj.loop : true;
        this.gap = obj.gap || 2000
        this.#init();
      }
      #init () {
        this.#swiper_dom_arr();

        this.#event()
        this.loop && this.loopHandler()
      }
      loopHandler () {
        let timer = setInterval(() => {
          this.index.value++
        }, this.gap)
      }
      #subscription (that) {
        return {
          set (obj, prop, value) {
            console.log(obj.value)
            if (obj.value != -1 && obj.value != that.arr.length) {
              that.#displacement_handler(value)
            }
            return Reflect.set(...arguments);
          },
        }
      }
      #swiper_dom_arr () {
        let swiperContainer = Utils.createDom(["swiper-container"]);
        let dom_arr = [...this.arr];
        dom_arr.push(this.arr[0]);
        dom_arr.unshift(this.arr[this.arr.length - 1]);
        let res = dom_arr.map(item => {
          let dom = Utils.createDom(["swiper-item"]);
          let img = document.createElement("img");
          img.src = item.src;

          img.ondragstart = function (event) {
            event.preventDefault();

            return false;
          };

          Utils.append(img, dom)
          return dom
        })
        res.forEach(item => {
          Utils.append(item, swiperContainer)
        })
        Utils.append(swiperContainer, this.container)
        swiperContainer.style.transform = `translateX(${(this.index.value - 1) * this.containerWidth}px)`;
        this.domArr = res;
        this.sp_container = swiperContainer

      }

      next () {
        this.index.value++;
      }
      pre () {
        this.index.value--;
      }
      #displacement_handler (value) {

        console.log("当前的value", value)
        this.sp_container.style.transform = `translateX(${(-value - 1) * this.containerWidth}px)`
        this.sp_container.style.transitionDuration = "300ms"

        let timer = setTimeout(() => {
          this.sp_container.style.transitionDuration = "0ms"
          if (value == -1) {
            this.sp_container.style.transform = `translateX(${-(this.arr.length) * this.containerWidth}px)`;
            this.index.value = this.arr.length - 1;
          } else if (value == this.arr.length) {
            this.sp_container.style.transform = `translateX(${(- 1) * this.containerWidth}px)`;
            this.index.value = 0
          }
          clearTimeout(timer)
        }, 300);



      }
      #event () {
        //this 此函数最外层的this 是指向实例化后的实例的，你可以理解成class
        let that = this;
        this.sp_container.addEventListener('pointerenter', Utils.debounce(enter, 50), false);
        let displacement
        let initialX
        let initTsf
        function enter (e) {
          this.addEventListener("pointerdown", Utils.debounce(down, 50), false)
          this.addEventListener("mouseup", release, false);
          this.addEventListener("pointerleave", release, false);
          function final () {

            if (displacement == 0) return
            if (Math.abs(displacement) > that.containerWidth / 2) {
              that.index.value = displacement > 0 ? that.index.value - 1 : that.index.value + 1;
            } else {
              that.#displacement_handler(that.index.value)
            }
            displacement = 0
          }
          function move (e) {
            let X = parseInt(e.clientX);
            displacement = X - initialX;
            let value = initTsf + displacement;
            this.style.transform = `translateX(${value}px)`

          }
          async function release () {

            if (displacement == 0) return
            ///
            Utils.debounce(final, 100)()
            ////
            that.sp_container.removeEventListener("pointermove", move)
            that.sp_container.removeEventListener("pointerdown", down, false)

          }
          function down (e) {

            initTsf = parseInt(getComputedStyle(this).getPropertyValue('transform').split(",")[4]);
            initialX = e.clientX;
            this.addEventListener("pointermove", move, false)
            displacement = 0;
          }
        }

      }
    }

    let silder = new Silder({
      container: ".container", arr, loop: true
    });
    next.onclick = () => {
      silder.next();
    }
    const preHandler = () => {
      silder.pre();
    }
    pre.onclick = preHandler;

  </script>
</body>

</html>